/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    app_netxduo.c
  * @author  MCD Application Team
  * @brief   NetXDuo applicative file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "app_netxduo.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define     DEMO_STACK_SIZE 2048
#define     DEMO_DATA       "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
#define     PACKET_SIZE     1536
#define     POOL_SIZE       ((sizeof(NX_PACKET) + PACKET_SIZE) * 16)
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
TX_THREAD               server_thread;

NX_PACKET_POOL          pool_0;
NX_IP                   ip_0;
NX_TCP_SOCKET           server_socket;
__attribute__((aligned(32))) UCHAR                   pool_buffer[POOL_SIZE];

ULONG error_counter;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
void server_thread_entry(ULONG thread_input);
void server_connect_received(NX_TCP_SOCKET *server_socket, UINT port);
void server_disconnect_received(NX_TCP_SOCKET *server_socket);
/* USER CODE END PFP */

/**
  * @brief  Application NetXDuo Initialization.
  * @param memory_ptr: memory pointer
  * @retval int
  */
UINT MX_NetXDuo_Init(VOID *memory_ptr)
{
  UINT ret = NX_SUCCESS;
  TX_BYTE_POOL *byte_pool = (TX_BYTE_POOL*)memory_ptr;

  /* USER CODE BEGIN MX_NetXDuo_MEM_POOL */
  (void)byte_pool;
  /* USER CODE END MX_NetXDuo_MEM_POOL */

  /* USER CODE BEGIN MX_NetXDuo_Init */
  CHAR *pointer;

  /* Setup the working pointer.  */
  pointer =  (CHAR *)byte_pool;

  /* Create the server thread.  */
  tx_thread_create(&server_thread, "Server Thread", server_thread_entry, 0,
                  pointer, DEMO_STACK_SIZE,
                  4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);

  pointer =  pointer + DEMO_STACK_SIZE;

  /* Initialize the NetX system.  */
  nx_system_initialize();

  /* Create a packet pool.  */
  if(nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pool_buffer, POOL_SIZE) != NX_SUCCESS) {
      Error_Handler();
  };

  /* Create the IP instance.  */
  if(nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(192, 168, 20, 10), 0xFFFFFF00UL, &pool_0, nx_stm32_eth_driver,
                  pointer, 2048, 1) != NX_SUCCESS) {
    Error_Handler();
  };
  pointer =  pointer + 2048;

  /* Enable ARP and ICMP.  */
  if(nx_arp_enable(&ip_0, (void *)pointer, 1024) != NX_SUCCESS) {
    Error_Handler();
  };
  pointer =  pointer + 1024;

  if(nxd_icmp_enable(&ip_0) != NX_SUCCESS) {
    Error_Handler();
  };

  /* Enable TCP.  */
  if(nx_tcp_enable(&ip_0) != NX_SUCCESS) {
    Error_Handler();
  };

  /* USER CODE END MX_NetXDuo_Init */

  return ret;
}

/* USER CODE BEGIN 1 */
void server_thread_entry(ULONG thread_input)
{
  UINT       status;
  NX_PACKET *packet_ptr;

  NX_PARAMETER_NOT_USED(thread_input);

  /* Wait 1 second for the IP thread to finish its initialization. */
  tx_thread_sleep(NX_IP_PERIODIC_RATE);

  /* Create a socket.  */
  status =  nx_tcp_socket_create(&ip_0, &server_socket, "Server Socket",
                                 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100,
                                 NX_NULL, server_disconnect_received);

  /* Check for error.  */
  if (status) {
      error_counter++;
  }

  /* Setup this thread to listen on port 8089.  */
  status =  nx_tcp_server_socket_listen(&ip_0, 8089, &server_socket, 5, server_connect_received);

  /* Check for error.  */
  if (status) {
      error_counter++;
  }

  /* Loop to create and establish server connections.  */
  while (1) {
      /* Accept a client socket connection.  */
      status =  nx_tcp_server_socket_accept(&server_socket, NX_WAIT_FOREVER);

      /* Check for error.  */
      if (status) {
          error_counter++;
      }

      /* Allocate a packet.  */
      status =  nx_packet_allocate(&pool_0, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);

      /* Check status.  */
      if (status != NX_SUCCESS) {
          error_counter++;
          continue;
      }

      /* Write ABCs into the packet payload!  */
      nx_packet_data_append(packet_ptr, DEMO_DATA, sizeof(DEMO_DATA), &pool_0, TX_WAIT_FOREVER);

      /* Send the packet to the client.  */
      status =  nx_tcp_socket_send(&server_socket, packet_ptr, NX_IP_PERIODIC_RATE);

      /* Check for error.  */
      if (status) {
          error_counter++;
          nx_packet_release(packet_ptr);
      }

      /* Disconnect the server socket.  */
      status =  nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE);

      /* Check for error.  */
      if (status) {
          error_counter++;
      }

      /* Unaccept the server socket.  */
      status =  nx_tcp_server_socket_unaccept(&server_socket);

      /* Check for error.  */
      if (status) {
          error_counter++;
      }

      /* Setup server socket for listening again.  */
      status =  nx_tcp_server_socket_relisten(&ip_0, 8089, &server_socket);

      /* Check for error.  */
      if (status) {
          error_counter++;
      }
  }
}

void server_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port)
{
  /* Check for the proper socket and port.  */
  if ((socket_ptr != &server_socket) || (port != 8089)) {
      error_counter++;
  }
}

void server_disconnect_received(NX_TCP_SOCKET *socket)
{
  /* Check for proper disconnected socket.  */
  if (socket != &server_socket) {
      error_counter++;
  }
}
/* USER CODE END 1 */
